package org.grayrabbit.cms.publish.service.impl;

import java.io.ByteArrayOutputStream;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.grayrabbit.cms.entity.Admin;
import org.grayrabbit.cms.entity.PublishLog;
import org.grayrabbit.cms.entity.PublishTask;
import org.grayrabbit.cms.entity.Site;
import org.grayrabbit.cms.publish.api.Generatable;
import org.grayrabbit.cms.publish.api.PublishInfo;
import org.grayrabbit.cms.publish.api.Publishable;
import org.grayrabbit.cms.publish.gc.PublishTaslGC;
import org.grayrabbit.cms.publish.generate.DeamonThread;
import org.grayrabbit.cms.publish.generate.factory.AbstractFactory;
import org.grayrabbit.cms.service.publish.PublishTaskService;
import org.grayrabbit.cms.util.MD5;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class PublishableImpl  implements Publishable{
	private  static Logger log = LoggerFactory.getLogger(PublishableImpl.class);
	@Autowired
	@Qualifier("defaultGenerator")
	private Generatable generatable;
	
	@Autowired
	@Qualifier("publishTaskServiceImpl")
	private PublishTaskService publishTaskService;
	
	@Transactional
	public String publish(Site site, String genType, String genMode,List<String> targetIds, Admin currentAdmin, String clientIp,Boolean isAuto,Integer pageSize,Integer pageNum) {
		//相同任务只执行一次。
		String taskId = "-1";
		String taskDesc = getTaskName(genType,genMode,targetIds);
		String taskName = MD5.getMD5Str(taskDesc);
		log.info("Current Task name is {}",taskName);
		if(!existTask(taskName)){//如果不存在已有任务的相关总任务数时，才进行发布任务
			PublishTaslGC.start();//启动任务垃圾回收
			log.info("Current Task not exist");
			PublishTask publishTask = publishTaskService.create(currentAdmin,taskName,taskDesc,isAuto);//md5的名字解析
			taskId = publishTask.getTaskId();
			synchronized (AbstractFactory.LOCK) {
				AbstractFactory.PUBLISHMAP.put(taskName, publishTask.getTaskId());
				AbstractFactory.PUBLISHSTATUS.put(taskName, Boolean.TRUE);//设为可运行状态
			}
			DeamonThread dt = new DeamonThread(genType,genMode,targetIds,site,currentAdmin,clientIp,publishTask,generatable);
			dt.setPageNum(pageNum==null?0:pageNum.intValue());
			dt.setPageSize(pageSize==null?0:pageSize.intValue());
			Thread thread = new Thread(dt);
			thread.setDaemon(true);
			thread.setName("DeamonThread:"+genType+":"+genMode+"启动发布线程");
			log.info("生成线程启动……");
			thread.start();
		}else{
			synchronized (AbstractFactory.LOCK) {
				taskId = AbstractFactory.PUBLISHMAP.get(taskName);
			}
		}
		return taskId;
	}
	
	private boolean existTask(String taskName){
		if(AbstractFactory.percent.containsKey(taskName + AbstractFactory.TOTAL)){
			int total = AbstractFactory.percent.get(taskName + AbstractFactory.TOTAL).intValue();
			int finished = AbstractFactory.percent.get(taskName + AbstractFactory.FINISHED).intValue();
			if(total <= finished){//当完成数与总数相等时，表示任务已完成，即上一任务结束，该任务即不存在，即以新任务形式出现
				return false;
			}else{
				return true;
			}
		}
		return false;
	}
	
	public ByteArrayOutputStream preview(Site site,String genType,List<String> targetIds,Admin currentAdmin, String clientIp) throws Exception{
		return generatable.preview(site,genType,targetIds,currentAdmin);
	}
	//获取任务名，即唯一的任务ID
	private String getTaskName(String genType, String genMode,List<String> targetIds){
		String ids="";
		for(String id:targetIds){
			ids+=id+"_";
		}
		return genType+"_"+genMode+"_"+ids;
	}
	
	@Transactional(readOnly=true)
	public PublishInfo read(String taskId,Integer offset) {
		PublishInfo pi = new PublishInfo();
		pi.setPublishKey(taskId);
		if(StringUtils.isNotBlank(taskId)){
			PublishTask publishTask = publishTaskService.getPublishTask(taskId);
			pi.setSuccessNum(publishTask.getCreateCount()==null?0:publishTask.getCreateCount().intValue());
			pi.setFailureNum(publishTask.getErrorCount()==null?0:publishTask.getErrorCount().intValue());
			pi.setTotal(publishTask.getTotal()==null?0:publishTask.getTotal().intValue());
			
			int percent  = pi.getTotal()==0?0:((pi.getFailureNum() +pi.getSuccessNum()) * 100)/pi.getTotal();
			pi.setPercent(percent>100?100:percent);
			pi.setOver(PublishTask.STATUS_STOP.equals(publishTask.getTaskStatus())||pi.getPercent()==100);//是否已停止
			List<PublishLog> logs  = publishTaskService.readPublishLogs(taskId,offset==null?0:offset.intValue());
			for(PublishLog log : logs){
				if(log.getIsError() !=null && log.getIsError().booleanValue()){
					pi.addLogInfo(log.getPublishInfo(), log.isFinished(), log.getPublishTime(),true);
				}else{
					pi.addLogInfo(StringUtils.isBlank(log.getHtmlPath())?log.getPublishInfo():log.getHtmlPath(), log.isFinished(), log.getPublishTime(),false);
				}
			}
		}
		return pi;
	}

	public void stop(String publishKey) {
		if(existTask(MD5.getMD5Str(publishKey))){
			synchronized (AbstractFactory.LOCK) {
				AbstractFactory.PUBLISHSTATUS.put(publishKey, Boolean.FALSE);//标识false为停止运行，true为运行状态
			}
		}
	}

}
